<?php
/**
 * @link http://www.tpframe.com/
 * @copyright Copyright (c) 2017 TPFrame Software LLC
 * @author 510974211@qq.com
 * 同步问题请使用锁处理
 */
namespace tpfcore\payment;
use tpfcore\base\Payment;
use tpfcore\helpers\StringHelper;
use tpfcore\lock\LockSystem;

class Weixin extends Payment{
	protected $gatewayUrl = 'https://openapi.alipay.com/gateway.do';
	protected $appId = null;
	protected $rsaPrivateKey = null;
	protected $alipayrsaPublicKey = null;
	protected $signType = "RSA2";

	/**
	 * 构造方法，配置应用信息
	 * @param array $token 
	 	$pay_config=[
            'APPID'=>'wx7115a96141f27e1b',
            'MCHID'=>'1488524592',
            'KEY'=>'saasFAFfasFAA231AWf3a1f30efa31fw',
            'APPSECRET'=>'16416e829b1ec1f573db5da26458c845'
        ];
	 */
	public function __construct($config=[],$callback=[]){
		//设置SDK类型
		$class = get_class($this);

		$this->Callback=empty($callback)?SITE_PATH."/payment/pay/weixin_notify":$callback['notify_url'];		//设置回调地址

        $this->Return_url=empty($callback)?SITE_PATH."/payment/pay/weixin_notify":$callback['return_url'];      //设置同步地址
	
		$this->Type = strtoupper(substr($class, 0, strlen($class)-3));

		//获取应用配置
		if(empty($config['APPID']) || empty($config['MCHID']) || empty($config['KEY']) || empty($config['APPSECRET'])){
			throw new \Exception('请先配置好你的参数');
		} else {
			new \WxPayConfig($config);
		}
	}

	/*
	* $pay_param	支付配置参数
	* $handle 		支付手柄 默认app
		$pay_param=[
			'body'=>"【TPFrame】钱包充值",		// 商品描述
			'out_trade_no'=>date('Ymdhis').rand(10000,99999),		// 商户订单号 
			'total_fee'=>"1000",			//总金额
			'notify_url'=>"http://xx.com/pay/notify",	//通知地址
			'trade_type'=>"APP"							//交易类型
		];
	*/
	public function pay($pay_param,$handle="app"){
		$payment_way="pay_".$handle;
		return $this->$payment_way($pay_param);
	}

	/*
		app支付
		$pay_param=[
			'body'=>"【TPFrame】钱包充值",		// 商品描述
			'attach'=>'充值',					// 附加数据  否
			'out_trade_no'=>date('Ymdhis').rand(10000,99999),		// 商户订单号 
			'total_fee'=>"1000",			//总金额
			'time_start'=>date("YmdHis"),	//交易起始时间	否
			'goods_tag'=>"商品支付",		//订单优惠标记	否
			'notify_url'=>"http://xx.com/pay/notify",	//通知地址
			'trade_type'=>"APP"							//交易类型
		];
	*/
	private function pay_app($pay_param){
		if(!array_key_exists("body",$pay_param) || !array_key_exists("out_trade_no",$pay_param) || !array_key_exists("total_fee",$pay_param) || !array_key_exists("notify_url",$pay_param) || !array_key_exists("trade_type",$pay_param)){
			return [1,"支付必须参数缺失"];
		}
		$weixin=new \WxPayUnifiedOrder();
        $weixin->SetBody($pay_param['body']);
        $weixin->SetAttach(isset($pay_param['attach'])?$pay_param['attach']:"");
        $weixin->SetOut_trade_no($pay_param['out_trade_no']);     // 订单号
        $weixin->SetTotal_fee($pay_param['total_fee']);
        $weixin->SetTime_start(isset($pay_param['time_start'])?$pay_param['time_start']:date("YmdHis"));
        $weixin->SetGoods_tag(isset($pay_param['goods_tag'])?$pay_param['goods_tag']:"");
        $weixin->SetNotify_url($this->Callback);//异步回调
        $weixin->SetTrade_type($pay_param['trade_type']);
        $order_ = \WxPayApi::unifiedOrder($weixin);         		// 统一下单
        $NonceStr=StringHelper::get_random_string(32);      // 随机生成不长于32位的字符串
        //二次计算签名参数注意：【package：prepay_id=(统一下单返回的prepay_id)】
        $data = [
            'appid' => $order_['appid'],
            'noncestr' => $NonceStr,
            'partnerid' => $order_['mch_id'],
            'prepayid' => $order_['prepay_id'],
            'package'=>'Sign=WXpay',
            'timestamp' => time()
        ];

        $sign=(new \WxPayDataBase)->MakeSign();  // 生成微信签名
        
        $data['sign']=$sign;

        if (!empty($order_)) {
            return [0,"微信支付sign",$data];
        }else{
            return [1,"签名失败或者未开通相关权限！"];
        }
	}
	/*
		公众号支付
        ex:
        $pay_param=[
            'body'=>"【TPFrame】钱包充值",        // 商品描述
            'out_trade_no'=>date('Ymdhis').rand(10000,99999),       // 商户订单号 
            'total_fee'=>"1000",            //总金额
            'notify_url'=>"http://xx.com/pay/notify",   //通知地址
            'trade_type'=>"JSAPI"                         //交易类型
        ];
        
        // 锁处理开始 使用Memcache前请先安装Memcache
        try{
            //创建锁(推荐使用MemcacheLock)  
            $lockSystem = new LockSystem(LockSystem::LOCK_TYPE_MEMCACHE);               
            //获取锁  
            $lockKey = $pay_param['out_trade_no'];
            $lockSystem->getLock($lockKey,8);

            // 同步数据处理区域
            $result=(new Weixin(Core::loadModel("Payment")->getPaymentConfig("weixin",'mp')))->pay($pay_param,"mp");

            //释放锁  
            $lockSystem->releaseLock($lockKey); 
        }catch (Exception $e)  
        {
            //释放锁  
            $lockSystem->releaseLock($lockKey);
        }
        // 锁处理结束

        return $this->fetch('wx_jspay',[
            'jsApiParameters'=>$result['jsApiParameters'],
            'editAddress'=>$result['editAddress'],
            'succeed'=>'success.html',
            'fail'=>'error.html'
        ]);
	*/
	private function pay_mp($pay_param){
        $tools = new \JsApiPay();
        $openId = $tools->GetOpenid();			//获取openid
        $weixin = new \WxPayUnifiedOrder();		//统一下单类
       	$weixin->SetBody($pay_param['body']);
        $weixin->SetAttach(isset($pay_param['attach'])?$pay_param['attach']:"");
        $weixin->SetOut_trade_no($pay_param['out_trade_no']);     // 订单号
        $weixin->SetTotal_fee(isset($pay_param['total_fee'])?$pay_param['total_fee']*100:$pay_param['total_amount']*100);
        $weixin->SetTime_start(isset($pay_param['time_start'])?$pay_param['time_start']:"");
        $weixin->SetTime_expire(date("YmdHis", time() + 3600));//支付有效期
        $weixin->SetGoods_tag(isset($pay_param['goods_tag'])?$pay_param['goods_tag']:"");
        $weixin->SetNotify_url($this->Callback);//异步回调
        $weixin->SetTrade_type(isset($pay_param['trade_type'])?$pay_param['trade_type']:"JSAPI");
        $weixin->SetOpenid($openId);
        $weixin->SetAppid(\WxPayConfig::$APPID);
        $order_info = \WxPayApi::unifiedOrder($weixin);
        $jsApiParameters = $tools->GetJsApiParameters($order_info);		// 支付参数，传到模板中
        $editAddress = $tools->GetEditAddressParameters();				//获取共享收货地址js函数参数
        if($jsApiParameters && $editAddress){
        	return ['jsApiParameters'=>$jsApiParameters,'editAddress'=>$editAddress];
    	}else{
    		throw new Exception("支付参数获取失败");
    	}
	}
    /*
        微信小程序支付
        $pay_param=[
            'body'=>"【TPFrame】钱包充值",        // 商品描述
            'attach'=>'充值',                 // 附加数据  否
            'out_trade_no'=>date('Ymdhis').rand(10000,99999),       // 商户订单号 
            'total_fee'=>"1000",            //总金额
            'time_start'=>date("YmdHis"),   //交易起始时间    否
            'goods_tag'=>"商品支付",        //订单优惠标记    否
            'notify_url'=>"http://xx.com/pay/notify",   //通知地址
            'trade_type'=>"APP"                         //交易类型
            'openid'=>"wa1faw4f56we1ef",           用户openid 必须传递
        ];
    */
    private function pay_wxapp($pay_param){
        $tools = new \JsApiPay();
        $weixin = new \WxPayUnifiedOrder();     //统一下单类
        $weixin->SetBody($pay_param['body']);
        $weixin->SetAttach(isset($pay_param['attach'])?$pay_param['attach']:"支付");
        $weixin->SetOut_trade_no($pay_param['out_trade_no']);     // 订单号
        $weixin->SetTotal_fee(isset($pay_param['total_fee'])?$pay_param['total_fee']*100:$pay_param['total_amount']*100);
        $weixin->SetTime_start(isset($pay_param['time_start'])?$pay_param['time_start']:"");
        $weixin->SetTime_expire(date("YmdHis", time() + 3600));     //支付有效期
        $weixin->SetGoods_tag(isset($pay_param['goods_tag'])?$pay_param['goods_tag']:"");
        $weixin->SetNotify_url($this->Callback);    //异步回调
        $weixin->SetTrade_type(isset($pay_param['trade_type'])?$pay_param['trade_type']:"JSAPI");
        $weixin->SetOpenid($pay_param['openid']);
        //$weixin->SetAppid(\WxPayConfig::$APPID);
        $order_info = \WxPayApi::unifiedOrder($weixin);
        // 再次签名
        $jsApiParameters = $tools->GetJsApiParameters($order_info);     // 支付参数，传到模板中
        if($jsApiParameters){
            return ['jsApiParameters'=>$jsApiParameters];
        }else{
            throw new Exception("支付参数获取失败");
        }
    }
    /*
        PC支付
        ex:
        $pay_param=[
            'body'=>"【TPFrame】钱包充值",            // 商品描述
            'out_trade_no'=>date('Ymdhis').rand(10000,99999),       // 商户订单号 
            'total_fee'=>"1",            //总金额
            'notify_url'=>"http://heishi.aoeoe.cn/Pay/weixin_notify",   //通知地址
            'product_id'=>15482,                        //商品ID
            'trade_type'=>"NATIVE",                     //交易类型
            
        ];
        $url=(new Weixin(Core::loadModel("Payment")->getPaymentConfig("weixin",'pc')))->pay($pay_param,"pc");
        $img=\tpfcore\util\QRcode::png($url);
        echo "<img alt=\"模式二扫码支付\" src=\"".$img."\" style=\"width:150px;height:150px;\"/>";
        die;
    */
    private function pay_pc($pay_param){
        $notify = new \NativePay();

        $weixin = new \WxPayUnifiedOrder();     //统一下单类
        $weixin->SetBody($pay_param['body']);
        $weixin->SetAttach(isset($pay_param['attach'])?$pay_param['attach']:"");
        $weixin->SetOut_trade_no($pay_param['out_trade_no']);     // 订单号
        $weixin->SetTotal_fee($pay_param['total_fee']);
        $weixin->SetTime_start(isset($pay_param['time_start'])?$pay_param['time_start']:"");
        $weixin->SetTime_expire(date("YmdHis", time() + 3600));//支付有效期
        $weixin->SetGoods_tag(isset($pay_param['goods_tag'])?$pay_param['goods_tag']:"");
        $weixin->SetNotify_url($this->Callback);//异步回调
        $weixin->SetTrade_type($pay_param['trade_type']);
        $weixin->SetProduct_id("123456789");

        $result = $notify->GetPayUrl($weixin);
        return $result["code_url"];
    }
    /*
        微信H5支付
        $pay_param=[
            'body'=>"【TPFrame】钱包充值",            // 商品描述
            'out_trade_no'=>date('Ymdhis').rand(10000,99999),       // 商户订单号 
            'total_fee'=>"1",            //总金额
            'notify_url'=>"http://heishi.aoeoe.cn/Pay/weixin_notify",   //通知地址
            'trade_type'=>"MWEB",                         //交易类型
            'scene_info'=>[
                "h5_info"=>[
                    'type' => 'Wap',
                    'wap_url' => 'http://heishi.aoeoe.cn',
                    'wap_name' =>'【TPFrame】钱包充值'
                ]
            ]
        ];
        $url=(new Weixin(Core::loadModel("Payment")->getPaymentConfig("weixin",'wap')))->pay($pay_param,"wap");
    */
    private function pay_wap($pay_param){
        if(!array_key_exists("body",$pay_param) || !array_key_exists("out_trade_no",$pay_param) || !array_key_exists("total_fee",$pay_param) || !array_key_exists("notify_url",$pay_param) || !array_key_exists("trade_type",$pay_param)){
            return [1,"支付必须参数缺失"];
        }
        
        $weixin=new \WxPayUnifiedOrder();
        $weixin->SetBody($pay_param['body']);
        $weixin->SetOut_trade_no($pay_param['out_trade_no']);     // 订单号
        $weixin->SetTotal_fee($pay_param['total_fee']);
        $weixin->SetNotify_url($this->Callback);//异步回调
        $weixin->SetTrade_type($pay_param['trade_type']);
        $weixin->SetScene_info(json_encode($pay_param['scene_info']));
        $result = \WxPayApi::unifiedOrder($weixin);                 // 统一下单
        if($result['return_code']=="FAIL"){
            throw new \Exception("{$result['return_msg']}", 1);
        }
        $url = $result['mweb_url'].'&redirect_url='.$this->Return_url;  //redirect_url 是支付完成后返回的页面

        // 从网站弄下来的案例......
        /*$appid = 'wx141ace6be0284b0b';
        $mch_id = '72692212';//商户号
        $key = '6Ww0mXHfqtyKP2aGO7A35bv8prxgVi1E';//商户key

        $notify_url = "https://www.gujia.la/wxnativepay";//回调地址
        $wechatAppPay = new \wechatAppPay($appid, $mch_id, $notify_url, $key);

        $params['body'] = '估价啦';                       //商品描述
        $params['out_trade_no'] = $pay_param['out_trade_no'];    //自定义的订单号
        $params['total_fee'] = '1';                       //订单金额 只能为整数 单位为分
        $params['trade_type'] = 'MWEB';                   //交易类型 JSAPI | NATIVE | APP | WAP 
        $params['scene_info'] = '{"h5_info": {"type":"Wap","wap_url": "https://www.diugou.com","wap_name": "估价啦"}}';

        $result = $wechatAppPay->unifiedOrder($params);
        print_r($result);
        die;
        $url = $result['mweb_url'].'&redirect_url=https%3A%2F%2Fwww.gujia.la';//redirect_url 是支付完成后返回的页面
        */
        
        return $url;
    }
}